package concurrency.lock;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 *
 * 从代码实现来看，CLH比MCS要简单得多。
 * 从自旋的条件来看，CLH是在前驱节点的属性上自旋，而MCS是在本地属性变量上自旋。
 * 从链表队列来看，CLH的队列是隐式的，CLHNode并不实际持有下一个节点；MCS的队列是物理存在的。
 * CLH锁释放时只需要改变自己的属性，MCS锁释放则需要改变后继节点的属性。
 *
 * 基于隐式的链表实现的公平锁
 * @Author: hao.zhang
 * @Date: 9/6/19 3:50 PM
 */
public class SimpleCLHLock {

    private volatile CLHNode tail;

    private static final AtomicReferenceFieldUpdater<SimpleCLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater
        .newUpdater(SimpleCLHLock.class, CLHNode.class, "tail");


    public void lock(CLHNode currentThread) {
        CLHNode preNode = UPDATER.getAndSet(this, currentThread);
        if (preNode != null) {
            // 自旋前驱节点
            while (preNode.isLocked) {}
        }
    }


    public void unlock(CLHNode currentThread) {
        if (!UPDATER.compareAndSet(this, currentThread, null)) {
            // 表示当前线程有后继节点，需要改变自己的属性，才能让后继节点获取到锁
            currentThread.isLocked = false;
        }
    }


    static class CLHNode {
        private volatile boolean isLocked = true;
    }
}
